package com.coocaa.x.service.litecache.data.client;

import android.graphics.Bitmap;

import com.coocaa.x.framework.utils.ImageUtils;
import com.coocaa.x.framework.utils.LogUtils;
import com.coocaa.x.service.litecache.data.common.LiteCacheObject;
import com.coocaa.x.service.litecache.data.common.LiteCacheObject.LiteCacheObjectCacheListener;
import com.coocaa.x.service.litecache.data.common.LiteCacheObject.LiteCacheObjectLockListener;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * Created by lu on 15-3-14.
 */
public class LiteImageCache {
    private static ThreadPoolExecutor executor = null;

    static {
        executor = new ThreadPoolExecutor(2, 2, 10, TimeUnit.DAYS,
                new LinkedBlockingQueue<Runnable>(), new ThreadFactory() {
            @Override
            public Thread newThread(Runnable r) {
                Thread thread = new Thread(r, "LiteImageCacheDecodeThread");
                return thread;
            }
        });
        executor.prestartAllCoreThreads();
    }

    private static LiteImageCache instance = new LiteImageCache();

    public static LiteImageCache getInstance() {
        return instance;
    }

    public static interface LiteImageCacheLoadListener {
        void onImageLoaded(LiteImageCacheObject obj);
    }

    public static class LiteImageCacheObject {
        private String url = null;
        private Bitmap bitmap = null;

        public LiteImageCacheObject(String url, Bitmap bitmap) {
            this.url = url;
            this.bitmap = bitmap;
        }

        public String getUrl() {
            return url;
        }

        public synchronized Bitmap getBitmap() throws Exception {
            if (bitmap.isRecycled())
                throw new Exception("You are try to get a recycled cacheObject!! url:" + url);
            return bitmap;
        }

        public void recyle() {
            LiteImageCache.getInstance().recyle(this);
        }
    }

    private Map<String, LiteImageCacheObject> bitmapCache = new HashMap<String, LiteImageCacheObject>();
    private Map<Bitmap, Integer> refCountCache = new HashMap<Bitmap, Integer>();

    public void load(final String url, final LiteImageCacheLoadListener listener, final int width,
                     final int height) {
        load(url, listener, width, height, 100);
    }

    public void load(final String url, final LiteImageCacheLoadListener listener, final int width,
                     final int height, final int alpha) {
        try {
            LiteCacheObject.cache(url, new LiteCacheObjectCacheListener() {
                @Override
                public void onLiteCacheObjectCached(boolean success, LiteCacheObject obj) {
                    try {
                        LogUtils.i("Image", "onLiteCacheObjectCached success:" + success);
                        if (!success) {
                            try {
                                listener.onImageLoaded(null);
                            } catch (Exception e) {
                            }
                            return;
                        }
                        obj.lock(new LiteCacheObjectLockListener() {
                            @Override
                            public void onLiteCacheObjectLocked(final LiteCacheObject obj,
                                                                boolean success, final String content) {
                                if (!success)
                                    return;
                                LogUtils.i("Image", "onLiteCacheObjectLocked success:" + success);
                                executor.execute(new Runnable() {
                                    @Override
                                    public void run() {
                                        LogUtils.i("Image", "decode");
                                        LiteImageCacheObject cache = null;
                                        synchronized (bitmapCache) {
                                            cache = bitmapCache.get(url);
                                            if (cache == null) {
                                                Bitmap bitmap = ImageUtils.decodeSampledBitmapFromFile(content, width, height);
                                                if (alpha < 100) {
                                                    bitmap = ImageUtils.alpha(bitmap, alpha);
                                                }
                                                if (width > 0) {
                                                    bitmap = ImageUtils.scale(bitmap, width, height);
                                                }
                                                cache = new LiteImageCacheObject(url, bitmap);
                                                bitmapCache.put(url, cache);
                                                System.gc();
                                                synchronized (refCountCache) {
                                                    try {
                                                        bitmap = cache.getBitmap();
                                                        Integer count = refCountCache.get(bitmap);
                                                        if (count == null)
                                                            count = 1;
                                                        else
                                                            count += 1;
                                                        LogUtils.i("PP", "load url:" + url + " count:"
                                                                + count);
                                                        refCountCache.put(bitmap, count);
                                                    } catch (Exception e) {
                                                        e.printStackTrace();
                                                    }
                                                }
                                            }
                                        }
                                        LogUtils.i("Image", "draw");
                                        listener.onImageLoaded(cache);
                                        try {
                                            obj.unlock();
                                            LogUtils.i("Image", "unlocked");
                                        } catch (Exception e) {
                                            e.printStackTrace();
                                        }
                                    }
                                });
                            }
                        });
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void recyle(LiteImageCacheObject obj) {
        synchronized (bitmapCache) {
            LiteImageCacheObject _obj = bitmapCache.get(obj.getUrl());
            if (_obj != null) {
                synchronized (refCountCache) {
                    try {
                        Bitmap bitmap = _obj.getBitmap();
                        Integer count = refCountCache.get(bitmap);
                        if (count != null) {
                            count -= 1;
                            LogUtils.i("PP", "recyle url:" + obj.getUrl() + " count:" + count);
                            if (count == 0) {
                                if (bitmap != null && !bitmap.isRecycled()) {
                                    bitmap.recycle();
                                }
                                synchronized (bitmapCache) {
                                    bitmapCache.remove(obj.getUrl());
                                }
                                refCountCache.remove(bitmap);
                                System.gc();
                            } else
                                refCountCache.put(bitmap, count);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}
